package com.runa.monitor.platinterface.netservice.equipment;

import com.runa.monitor.comm.dto.Archive;
import com.runa.monitor.comm.dto.Node;
import com.runa.monitor.comm.dto.newComm.ValveVO;
import com.runa.monitor.platinterface.backwork.function.TaskFunction;
import com.runa.monitor.platinterface.netservice.connect.commstatus.CommStatus;
import com.runa.persistence.SerializeUtil;
import com.runa.rccprotocol.dto.AffirmDeny;
import com.runa.rccprotocol.dto.equdata.EquData;
import com.runa.rccprotocol.dto.param.ExtendParam;
import okhttp3.*;
import org.apache.commons.lang.StringUtils;

import java.io.IOException;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

public class TFNBDriver extends NetEqu<String> {

    private String url;

    private String username;

    private String password;

    private String token;

    private OkHttpClient httpClient;

    public TFNBDriver(String serial, Integer timeout, String url, String username, String password) {
        super(serial, timeout);
        this.url = url;
        this.username = username;
        this.password = password;
        this.httpClient = new OkHttpClient()
                .newBuilder()
                .callTimeout(timeout, TimeUnit.MILLISECONDS)
                .build();
    }

    private void getToken() {
        try {
            Response response = httpClient.newCall(new Request.Builder()
                    .url(this.url+"/User/getToken?username="+username+"&password="+password)
                    .get()
                    .build()).execute();
            this.token = (String) SerializeUtil.json2map(response.body().string()).get("data");
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    @Override
    public void readNodeEqu(List<Node> nodes, TaskFunction function, EquData.EquDataType type) {
        if (type == EquData.EquDataType.PUBLIC_UNIT) {
            String valves = SerializeUtil.obj2json(nodes.stream().map(Node::getSerial).collect(Collectors.toList()));
            try {
                if (StringUtils.isEmpty(token)) {
                    getToken();
                }
                Response response = null;
                if (valves != null) {
                    response = httpClient.newCall(new Request.Builder().url(this.url+"/SecondaryControl/getValveStatuss")
                            .header("token",token)
                            .post(RequestBody.create(valves,
                                    MediaType.parse("application/json; charset=utf-8")))
                            .build()).execute();
                }
                Map<String, Object> result = SerializeUtil.json2map(response.body().string());
                if (1004 == (Integer) result.get("code")) {
                    getToken();
                    readNodeEqu(nodes, function, type);
                }
                if (1000 == (Integer) result.get("code")) {
                    List<Map<String, Object>> data = (List<Map<String, Object>>) result.get("data");
                    function.doApply(CommStatus.OK, data.stream().filter(Objects::nonNull).map(valve -> {
                        ValveVO valveVO = new ValveVO();
                        valveVO.setValveSerial(valve.get("networkNumber")+"-"+valve.get("deviceAddress"));
//                        valveVO.setSupplyTemp(((Double) valve.get("supplyTemperature")).floatValue());
                        valveVO.setReturnTemp(((Double) valve.get("returnTemperature")).floatValue());
                        valveVO.setActOpen(((Double) valve.get("returnValveFeedback")).floatValue());
                        valveVO.setRemoteSet(((Double) valve.get("returnValveSetpoint")).floatValue());
//                        valveVO.setSignal((String) valve.get("signalStrength"));
                        return valveVO;
                    }).collect(Collectors.toList()));
                }
            } catch (IOException e) {
                function.doApply(CommStatus.OffLine, nodes);
            }
        }
    }

    @Override
    public void setNodeEquArchive(List<Archive> archives, TaskFunction function) {

    }

    @Override
    public void clearNodeEquArchive(TaskFunction function) {

    }

    @Override
    public void valveOnOffControl(List<Node> nodeList, boolean ifLock, Integer opening, TaskFunction function) {

    }

    @Override
    public void readNodeRecord(List<Integer> indexes, TaskFunction function) {

    }

    @Override
    public void sentPublicUnitRecord(List<Node> nodeList, Integer model, Map param, TaskFunction function) {
        for (Node valve : nodeList) {
            function.setStatus(valve);
            switch (model) {
                case 1:
                    if (StringUtils.isEmpty(token)) {
                        getToken();
                    }
                    try {
                        Response response = httpClient.newCall(new Request.Builder()
                                .url(this.url+"/SecondaryControl/setValveOpening?valveCode="
                                        +valve.getSerial()+"&opening="
                                        +param.get("targetValue"))
                                .header("token", token)
                                .build()).execute();
                        if ((Integer) SerializeUtil.json2map(response.body().string()).get("code") == 1000) {
                            function.doApply(CommStatus.OK, new AffirmDeny(){
                                @Override
                                public Boolean getData() {
                                    return true;
                                }
                            });
                        } else {
                            function.doApply(CommStatus.OK, new AffirmDeny(){
                                @Override
                                public Boolean getData() {
                                    return false;
                                }
                            });
                        }
                    } catch (IOException e) {
                        throw new RuntimeException(e);
                    }
                    break;
                case 2:
                case 3:
                case 4:
                    break;
                default:
            }
        }
    }

    @Override
    public void sentPublicUnitModel(List<Node> nodeList, boolean model, TaskFunction function) {

    }

    @Override
    public void sentExtendParam(ExtendParam param, TaskFunction function) {

    }

    @Override
    public void readPublicUnitRecord(Node valve, Integer model, TaskFunction function) {

    }

    @Override
    public void readPublicUnitAndMeter(Node valve, Node meter, TaskFunction function) {

    }

    @Override
    public void heartbeatUpdate() {

    }

    @Override
    public boolean heartStop() {
        return false;
    }
}
